//
//  VPaiConnectionManager.swift
//  VPai
//
//  Created by devel on 16/9/19.
//  Copyright © 2016年 viatech. All rights reserved.
//

import Foundation
import tcp2usb

class VPaiConnectionManager: NSObject, VPaiDiscoveryListener{
    
    private static let TAG = "VPaiConnectionManager"
    private static let KEY_CONNECT_DEVICE_ID = "key_connect_device_id"
    //单例模式
    class var shareInstance : VPaiConnectionManager{
        struct Static {
            static var instance: VPaiConnectionManager?
            static var token: dispatch_once_t = 0
        }
        
        dispatch_once(&Static.token){
            Static.instance = VPaiConnectionManager()
        }
        
        return Static.instance!
    }
    
    func registerListener(listener : VPaiConnectionListener) {
        listenerList.registerListener(listener)
    }
    
    func unregisterListener(listener : VPaiConnectionListener) {
        listenerList.unregisterListener(listener)
    }
    
    func retryFindDevice(){
        VPaiDiscovery.shareInstance.startDiscover(true)
    }
    
    var currentConnectVPai : VPaiDevice?{
        get{
            if ctrlConnected && mediaConnected {
                return current
            }else {
                return nil
            }
        }
    }
    
    //private value and function
    private let listenerList = ListenerList()
    private let RETRY_TIMEOUT : Double = 5
    private var current: VPaiDevice?
    private var vpaiCtrlWebSocketEvent : VPaiCtrlWebSocketEvents?
    private var vpaiMediaWebSocketEvent : VPaiMediaWebSocketEvents?
    private var retryCtrlTimer : NSTimer?
    private var retryMediaTimer : NSTimer?
    private var ctrlConnected = false
    private var mediaConnected = false
    private let upgradeManager : VPaiUpgradeManager
    
    private override init() {
      upgradeManager = VPaiUpgradeManager()
        
        super.init()
        
        vpaiCtrlWebSocketEvent = VPaiCtrlWebSocket.shareInstance.registerEvent()
        vpaiCtrlWebSocketEvent?.onWebSocketOpen = {
            self.retryCtrlTimer?.invalidate()
            self.retryCtrlTimer = nil
            if let device = self.current {
                VPaiCtrlWebSocket.shareInstance.getDeviceInfo{args in
                    if args.ret == 0 {
                        device.vpaiDeviceInfo = VPaiDeviceInfo.parseFromJson(args.json)
                        if let info = self.upgradeManager.getUpgradeInfo(device.vpaiDeviceInfo) {
                            self.upgradeManager.startUpgrade(info)
                        }
                    }
                }
               // device.remoteMediaSource.refresh()
                VPaiCtrlWebSocket.shareInstance.setDateTime(DateTimeInfo()){args in
                    
                }
                VPaiCtrlWebSocket.shareInstance.setCurrentSystemLanguage(){args in
                    
                }
                
                self.ctrlConnected = true
                if self.ctrlConnected && self.mediaConnected{
                    self.listenerList.foreach({ (l : VPaiConnectionListener, index) in
                        l.onConnectedDevice(device)
                    })
                }
            }
        }
        vpaiCtrlWebSocketEvent?.onWebSocketClose = {
            if let device = self.current {
                
                self.ctrlConnected = false
                self.listenerList.foreach({ (l : VPaiConnectionListener, index) in
                    l.onConnectingDevice(device)
                })
                
                self.retryCtrlTimer?.invalidate()
                self.retryCtrlTimer = nil
                self.retryCtrlTimer = NSTimer.scheduledTimerWithTimeInterval(self.RETRY_TIMEOUT, target: self,
                     selector: #selector(VPaiConnectionManager.retryConnectCtrl(_:)), userInfo: nil, repeats: false)
            }
        }
        vpaiCtrlWebSocketEvent?.onDeviceInfo = {info in
            if let device = self.current {
                device.vpaiDeviceInfo = info
            }
        }
        
        vpaiMediaWebSocketEvent = VPaiMediaWebSocket.shareInstance.registerEvent()
        vpaiMediaWebSocketEvent?.onWebSocketOpen = {
            self.retryMediaTimer?.invalidate()
            self.retryMediaTimer = nil
            if let device = self.current {
                self.mediaConnected = true
                if self.ctrlConnected && self.mediaConnected{
                    self.listenerList.foreach({ (l : VPaiConnectionListener, index) in
                        l.onConnectedDevice(device)
                    })
                }
            }
        }
        vpaiMediaWebSocketEvent?.onWebSocketClose = {
            if let device = self.current {
                self.mediaConnected = false
                self.listenerList.foreach({ (l : VPaiConnectionListener, index) in
                    l.onConnectingDevice(device)
                })
                
                self.retryMediaTimer?.invalidate()
                self.retryMediaTimer = nil
                self.retryMediaTimer = NSTimer.scheduledTimerWithTimeInterval(self.RETRY_TIMEOUT, target: self,
                        selector: #selector(VPaiConnectionManager.retryConnectMedia(_:)), userInfo: nil, repeats: false)
            }
        }
        
        VPaiDiscovery.shareInstance.registerListener(self)
        VPaiDiscovery.shareInstance.startDiscover(true)
    }
    
    deinit{
      //  Log.info(VPaiConnectionManager.TAG, msg: "deinit()")
        VPaiDiscovery.shareInstance.unregisterListener(self)
        if let event = vpaiCtrlWebSocketEvent {
            VPaiCtrlWebSocket.shareInstance.unregisterEvent(event)
        }
        if let event = vpaiMediaWebSocketEvent {
            VPaiMediaWebSocket.shareInstance.unregisterEvent(event)
        }
    }
    
    func onDevicesChange(devices : [VPaiDevice]){
        if devices.count == 0 {
            if let device = current {
                self.listenerList.foreach({ (l : VPaiConnectionListener, index) in
                    l.onLostConnection(device)
                })
            }
            current = nil
            ctrlConnected = false
            mediaConnected = false
            VPaiCtrlWebSocket.shareInstance.closeWebSocket()
            VPaiMediaWebSocket.shareInstance.closeWebSocket()
            return
        }
        
        var needReconnect = true
        if let device = current {
            for d in devices {
                if device.deviceid == d.deviceid{
                    needReconnect = false
                    break
                }
            }
        }
        
        if let device = findBestDevice(devices){
            if needReconnect {
                self.listenerList.foreach({ (l : VPaiConnectionListener, index) in
                    l.onConnectingDevice(device)
                })
                connectVPai(device)
            }
        }
    }
    
    func retryConnectCtrl(t: NSTimer) {
        retryCtrlTimer?.invalidate()
        retryCtrlTimer = nil
        if let device = self.current {
            VPaiCtrlWebSocket.shareInstance.openWebSocket(device.ctrlUrl)
        }
    }
    
    func retryConnectMedia(t: NSTimer) {
        retryMediaTimer?.invalidate()
        retryMediaTimer = nil
        if let device = self.current {
            VPaiMediaWebSocket.shareInstance.openWebSocket(device.mediaUrl)
        }
    }
    
    func cancelCurrentConnect() {
        if let device = current {
            dispatch_async(dispatch_get_main_queue(), {
                self.listenerList.foreach({ (l : VPaiConnectionListener, index) in
                    l.onLostConnection(device)
                })
            })
        }
        current = nil
        ctrlConnected = false
        mediaConnected = false
        VPaiCtrlWebSocket.shareInstance.closeWebSocket()
        VPaiMediaWebSocket.shareInstance.closeWebSocket()
    }
    
    private func connectVPai(device: VPaiDevice) {
      //  Log.info(VPaiConnectionManager.TAG, msg: "connectVPai:\(device.toString())")

        let defs = NSUserDefaults.standardUserDefaults();
        defs.setValue(device.deviceid, forKey: VPaiConnectionManager.KEY_CONNECT_DEVICE_ID)
        current = device
        VPaiCtrlWebSocket.shareInstance.openWebSocket(device.ctrlUrl)
        VPaiMediaWebSocket.shareInstance.openWebSocket(device.mediaUrl)
    }
    
    private func findBestDevice(list : [VPaiDevice]) -> VPaiDevice? {
        var device : VPaiDevice? = nil
        
        let defs = NSUserDefaults.standardUserDefaults();
        if let old = defs.stringForKey(VPaiConnectionManager.KEY_CONNECT_DEVICE_ID){
            for d in list {
                if old == d.deviceid{
                    device = d
                    break;
                }
            }
        }
        
        if device == nil && list.count > 0 {
            device = list[0]
        }
        
        return device
    }
}

protocol VPaiConnectionListener : NSObjectProtocol {
    func onConnectingDevice(device : VPaiDevice)
    func onConnectedDevice(device : VPaiDevice)
    func onLostConnection(device : VPaiDevice)
}

extension VPaiConnectionListener {
    func onConnectingDevice(device : VPaiDevice){}
    func onConnectedDevice(device : VPaiDevice){}
    func onLostConnection(device : VPaiDevice){}
}